/*
 * CCVisu is a tool for visual graph clustering
 * and general force-directed graph layout.
 * This file is part of CCVisu.
 *
 * Copyright (C) 2005-2012  Dirk Beyer
 *
 * CCVisu is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * CCVisu is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with CCVisu; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Please find the GNU Lesser General Public License in file
 * license_lgpl.txt or http://www.gnu.org/licenses/lgpl.txt
 *
 * Dirk Beyer    (firstname.lastname@uni-passau.de)
 * University of Passau, Bavaria, Germany
 */
package org.sosy_lab.ccvisu.graph;

import static com.google.common.base.Preconditions.checkNotNull;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

public class Relation implements Iterable<Tuple> {

  private final Set<Tuple>       storedTuples;

  private final ArrayList<Tuple> innerList;


  public Relation() {
    this.storedTuples = Sets.newHashSet();
    this.innerList = Lists.newArrayList();
  }

  /** Copy constructor. */
  public Relation(Relation relation) {
    innerList = Lists.newArrayList(relation.innerList);
    storedTuples = Sets.newHashSet(relation.storedTuples);
  }

  public void addTuple(Tuple tuple) {
    innerList.add(tuple);
  }

  public void addTuple(String relationName, String sourceName, String targetName) {
    checkNotNull(sourceName, "Source must not be null.");
    checkNotNull(targetName, "Target must not be null.");

    // We don't need reflexive edges.
    if (!sourceName.equals(targetName)) {
      List<String> nodeTuples = new ArrayList<String>(2);
      nodeTuples.add(sourceName);
      nodeTuples.add(targetName);
      Tuple tuple = new Tuple(relationName, nodeTuples);

      if (storedTuples.add(tuple)) {
        // add new tuples
        innerList.add(tuple);
      }
    }
  }

  public void addTuple(String relationName, String sourceId, String targetId,
      Map<String, String> nameMap) {

    checkNotNull(sourceId);
    checkNotNull(targetId);

    addTuple(relationName, nameMap.get(sourceId), nameMap.get(targetId));
  }

  @Override
  public Iterator<Tuple> iterator() {
    return innerList.iterator();
  }

  /** Returns the number of tuples stored in this Relation. */
  public int size() {
    return innerList.size();
  }

  public boolean isEmpty() {
    return size() == 0;
  }

  public static void sort(Relation relation, Comparator<Tuple> comparator) {
    Collections.sort(relation.innerList, comparator);
  }
}
